#include "StdAfx.h"
#include "Board.h"

//===========================================================================
Board::Board(
    unsigned int size,
    EPieceType   user,
    EPieceType   computer
)   : m_board( NULL )
    , m_size( size )
    , m_user( user )
    , m_computer( computer )
    , m_blacks( 0 )
    , m_whites( 0 )
{
    this->Initialize();
}

//===========================================================================
Board::~Board( void )
{
    this->CleanUp();
}

//===========================================================================
const EPieceType * Board::GetPiece(
    const IPosition & position
) const {
    if( !this->IsValidPosition( position ) )
        return NULL;
    
    return &this->m_board[ position.GetX() ][ position.GetY() ];
}

//===========================================================================
void Board::Initialize( void )
{
    this->m_board = new EPieceType*[ this->m_size ];
    for( unsigned int i = 0; i < this->m_size; i++ )
        this->m_board[ i ] = new EPieceType[ this->m_size ];

    this->SetPieces();
}

//===========================================================================
void Board::CleanUp( void )
{
    if( this->m_board )
    {
        for( unsigned int i = 0; i < this->m_size; i++ )
            delete [] this->m_board[ i ];
        
        delete [] this->m_board;
        this->m_board = NULL;
    }

    this->m_size = 0;
    
    this->m_user     =
    this->m_computer = EPT_NONE;

    this->m_blacks =
    this->m_whites = 0;
}

//===========================================================================
void Board::SetPieces( void )
{
    const unsigned int rows =
        static_cast< unsigned int >( this->m_size / 2 * 0.75 );

    for( unsigned int i = 0; i < rows; i++ )
        for( unsigned int j = 0; j < this->m_size; j++ ) {
            if( ( i + j ) % 2 ) {
                this->m_board[ i ][ j ] = this->m_computer;
                this->IncreasePieceCount( this->m_computer );
            }
            else
                this->m_board[ i ][ j ] = EPT_NONE;
        }

    for( unsigned int i = rows; i < this->m_size - rows; i++ )
        for( unsigned int j = 0; j < this->m_size; j++ )
            this->m_board[ i ][ j ] = EPT_NONE;

    for( unsigned int i = this->m_size - rows; i < this->m_size; i++ )
        for( unsigned int j = 0; j < this->m_size; j++ ) {
            if( ( i + j ) % 2 ) {
                this->m_board[ i ][ j ] = this->m_user;
                this->IncreasePieceCount( this->m_user );
            }
            else
                this->m_board[ i ][ j ] = EPT_NONE;
        }
}

//===========================================================================
void Board::IncreasePieceCount(
    EPieceType piece
) {
    switch( piece )
    {
        case EPT_BLACK : this->m_blacks++; break;
        case EPT_WHITE : this->m_whites++; break;
        default : break;
    }
}

//===========================================================================
void Board::DecreasePieceCount(
    EPieceType piece
) {
    switch( piece )
    {
        case EPT_BLACK : this->m_blacks--; break;
        case EPT_WHITE : this->m_whites--; break;
        default : break;
    }

    assert( this->m_blacks >= 0 );
    assert( this->m_whites >= 0 );
}

//===========================================================================
bool Board::IsGameOver( void ) const
{
    std::cout << "white : " << this->m_whites << std::endl;
    std::cout << "black : " << this->m_blacks << std::endl;
    
    if( !this->m_blacks || !this->m_whites )
        return true;
    
    return false;
}

//===========================================================================
void Board::Show( void ) const
{
    assert( EPT_COUNT == 3 );
    
    char pices[ EPT_COUNT ] = {
        '.', 'X', 'O'
    };
    
    for( unsigned int i = 0; i < this->m_size; i++ ) {
        std::cout << i << "  ";
        
        for( unsigned int j = 0; j < this->m_size; j++ )
            std::cout << pices[ this->m_board[ i ][ j ] ] << " ";

        std::cout << std::endl;
    }
    
    std::cout << std::endl << "   ";
    for( unsigned int i = 0; i < this->m_size; i++ )
        std::cout << i << " ";
    std::cout << std::endl;
}

//===========================================================================
bool Board::Set(
    const IPosition & position,
          EPieceType  piece
) {
    if( !this->IsValidPosition( position ) )
        return false;

    if( EPT_NONE == piece ) {
        this->m_board[ position.GetX() ][ position.GetY() ] = piece;
        return true;
    }
    
    this->m_board[ position.GetX() ][ position.GetY() ] = piece;
    unsigned int x = position.GetX();
    if( !x || this->GetSize() - 1 == x )
        this->Take( position );
    
    return true;
}

//===========================================================================
bool Board::Take(
    const IPosition & position
) {
    if( !this->IsValidPosition( position ) )
        return false;
    
    EPieceType * piece = &this->m_board[ position.GetX() ][ position.GetY() ];
    if( !piece )
        return false;
    
    this->DecreasePieceCount( *piece );
    *piece = EPT_NONE;

    std::cout << "("
              << position.GetX()
              << ","
              << position.GetY()
              << ") is taken." << std::endl;

    return true;
}

//===========================================================================
bool Board::IsValidPosition(
    const IPosition & position
) const {
    if(    position.GetX() < this->m_size
        && position.GetY() < this->m_size )
        return true;

    return false;
}

//===========================================================================
void Board::Release( void )
{
    Board::Release( this );
}

//===========================================================================
void Board::Release( Board * board )
{
    if( board )
        delete board;
}

//===========================================================================
IBoard * CreateBoard(
    unsigned int size,
    EPieceType   user,
    EPieceType   computer
) {
    return new Board(
        size,
        user,
        computer
    );
}